﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Gmantis.Controls.DataGrid
{
    public class DataGridCellsRangeCollection : ICollection<DataGridCellsRange>, IEnumerable<DataGridCellsRange>, IEnumerable
    {
        // Fields
        private bool _isReadOnly;

        // Methods
        internal DataGridCellsRangeCollection(DataGridModel model, List<DataGridCellsRange> ranges, bool isReadOnly)
        {
            Func<int, DataGridRow> indexer = null;
            Func<int> count = null;
            Func<DataGridRow, bool> contains = null;
            Func<IEnumerable<DataGridRow>> enumerable = null;
            Func<int, DataGridColumn> func5 = null;
            Func<int> func6 = null;
            Func<DataGridColumn, bool> func7 = null;
            Func<IEnumerable<DataGridColumn>> func8 = null;
            this._isReadOnly = isReadOnly;
            this.Ranges = ranges;
            this.Model = model;
            if (indexer == null)
            {
                indexer = index => this.Model.Rows[this.GetSelectedRows()[index]];
            }
            if (count == null)
            {
                count = () => this.GetSelectedRows().Count;
            }
            if (contains == null)
            {
                contains = row => this.GetSelectedRows().Contains(row.Index);
            }
            if (enumerable == null)
            {
                enumerable = () => from rowDisplayIndex in this.GetSelectedRows() select this.Model.Rows[rowDisplayIndex];
            }
            this.Rows = new DataGridSelectedItemsCollection<DataGridRow>(indexer, count, contains, enumerable);
            if (func5 == null)
            {
                func5 = index => this.Model.Columns.OrderedColumns[this.GetSelectedColumns()[index]];
            }
            if (func6 == null)
            {
                func6 = () => this.GetSelectedColumns().Count;
            }
            if (func7 == null)
            {
                func7 = column => this.GetSelectedColumns().Contains(column.DisplayIndex);
            }
            if (func8 == null)
            {
                func8 = () => from columnDisplayIndex in this.GetSelectedColumns() select this.Model.Columns.OrderedColumns[columnDisplayIndex];
            }
            this.Columns = new DataGridSelectedItemsCollection<DataGridColumn>(func5, func6, func7, func8);
        }

        public void Add(DataGridCellsRange range)
        {
            if (this.IsReadOnly)
            {
                throw new InvalidOperationException("Collection can not be modified.");
            }
            if (!range.IsValid)
            {
                throw new ArgumentException("Specified range is not valid.");
            }
            this.Ranges.Add(range);
        }

        public void Clear()
        {
            if (this.IsReadOnly)
            {
                throw new InvalidOperationException("Collection can not be modified.");
            }
            this.Ranges.Clear();
        }

        public bool Contains(DataGridCellsRange range)
        {
            return this.Contains(range, true);
        }

        public bool Contains(DataGridCell cell, bool isEqualToARange)
        {
            foreach (DataGridCellsRange range in this.Ranges)
            {
                if (isEqualToARange ? (range.IsSingleCell() && (range == new DataGridCellsRange(cell))) : range.Contains(cell))
                {
                    return true;
                }
            }
            return false;
        }

        public bool Contains(DataGridCellsRange range, bool isEqualToARange)
        {
            if (isEqualToARange)
            {
                return this.Ranges.Contains(range);
            }
            foreach (DataGridCellsRange range2 in this.Ranges)
            {
                if (range2.Contains(range))
                {
                    return true;
                }
            }
            return false;
        }

        public bool Contains(DataGridColumn column, bool isEqualToARange)
        {
            foreach (DataGridCellsRange range in this.Ranges)
            {
                if (isEqualToARange ? (range.IsSingleColumn() && (range == new DataGridCellsRange(column))) : range.Contains(column))
                {
                    return true;
                }
            }
            return false;
        }

        public bool Contains(DataGridRow row, bool isEqualToARange)
        {
            foreach (DataGridCellsRange range in this.Ranges)
            {
                if (isEqualToARange ? (range.IsSingleRow() && (range == new DataGridCellsRange(row))) : range.Contains(row))
                {
                    return true;
                }
            }
            return false;
        }

        public void CopyTo(DataGridCellsRange[] array, int arrayIndex)
        {
            this.Ranges.CopyTo(array, arrayIndex);
        }

        public IEnumerator<DataGridCellsRange> GetEnumerator()
        {
            return this.Ranges.GetEnumerator();
        }

        private OrderedSet GetSelectedColumns()
        {
            OrderedSet set = new OrderedSet();
            foreach (DataGridCellsRange range in this.Ranges)
            {
                set.AddRange(range.TopLeftCell.Column.DisplayIndex, range.BottomRightCell.Column.DisplayIndex);
            }
            return set;
        }

        private OrderedSet GetSelectedRows()
        {
            OrderedSet set = new OrderedSet();
            foreach (DataGridCellsRange range in this.Ranges)
            {
                set.AddRange(range.TopLeftCell.Row.Index, range.BottomRightCell.Row.Index);
            }
            return set;
        }

        public bool Remove(DataGridCellsRange range)
        {
            if (this.IsReadOnly)
            {
                throw new InvalidOperationException("Collection can not be modified.");
            }
            int index = 0;
            bool flag = false;
            while (index < this.Ranges.Count)
            {
                DataGridCellsRange range2 = this.Ranges[index];
                if (range2.Intersects(range))
                {
                    flag = true;
                    DataGridCellsRange[] rangeArray = range2.Subtract(range);
                    this.Ranges.RemoveAt(index);
                    foreach (DataGridCellsRange range3 in rangeArray)
                    {
                        this.Ranges.Insert(index, range3);
                        index++;
                    }
                }
                else
                {
                    index++;
                }
            }
            return flag;
        }

        public bool Remove(DataGridColumn column)
        {
            if (this.IsReadOnly)
            {
                throw new InvalidOperationException("Collection can not be modified.");
            }
            DataGridCellsRange range = new DataGridCellsRange(column);
            return this.Remove(range);
        }

        public bool Remove(DataGridRow row)
        {
            if (this.IsReadOnly)
            {
                throw new InvalidOperationException("Collection can not be modified.");
            }
            DataGridCellsRange range = new DataGridCellsRange(row);
            return this.Remove(range);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        public override string ToString()
        {
            return ("{" + string.Join(" ", (from r in this.Ranges select r.ToString()).ToArray<string>()) + "}");
        }

        // Properties
        public DataGridSelectedItemsCollection<DataGridColumn> Columns { get; private set; }

        public int Count
        {
            get
            {
                return this.Ranges.Count;
            }
        }

        public bool IsReadOnly
        {
            get
            {
                return this._isReadOnly;
            }
        }

        private DataGridModel Model { get; set; }

        private List<DataGridCellsRange> Ranges { get; set; }

        public DataGridSelectedItemsCollection<DataGridRow> Rows { get; private set; }
    }
}
